package com.inventive.jmscache.server;

import com.hazelcast.nio.DataSerializable;
import com.inventive.jmscache.server.hazelcast.DataSerializationHelper;
import com.inventive.jmscache.server.utils.CollectionEnumeration;

import javax.jms.Message;
import javax.jms.JMSException;
import javax.jms.Destination;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.*;

/**
 * @author Grant Little <grant.little@coreservices.com.au>
 */
public class JmsCacheMessage implements Message, DataSerializable {

    protected String jmsMessageId;
    protected long jmsTimestamp = 0L;
    protected int priority;
    protected int deliveryMode;
    protected Map<String, Object> properties = null;
    protected Date addedTimestamp;

    public String getJMSMessageID() throws JMSException {
        return jmsMessageId;
    }

    public void setJMSMessageID(String s) throws JMSException {
        this.jmsMessageId = s;
    }

    public long getJMSTimestamp() throws JMSException {
        return jmsTimestamp;
    }

    public void setJMSTimestamp(long l) throws JMSException {
        this.jmsTimestamp = l;
    }

    public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
        return new byte[0];
    }

    public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException {
    }

    public void setJMSCorrelationID(String s) throws JMSException {
    }

    public String getJMSCorrelationID() throws JMSException {
        return null;
    }

    public Destination getJMSReplyTo() throws JMSException {
        return null;
    }

    public void setJMSReplyTo(Destination destination) throws JMSException {
    }

    public Destination getJMSDestination() throws JMSException {
        return null;
    }

    public void setJMSDestination(Destination destination) throws JMSException {
    }

    public int getJMSDeliveryMode() throws JMSException {
        return deliveryMode;
    }

    public void setJMSDeliveryMode(int deliveryMode) throws JMSException {
        this.deliveryMode = deliveryMode;
    }

    public boolean getJMSRedelivered() throws JMSException {
        return false;
    }

    public void setJMSRedelivered(boolean b) throws JMSException {
    }

    public String getJMSType() throws JMSException {
        return null;
    }

    public void setJMSType(String s) throws JMSException {
    }

    public long getJMSExpiration() throws JMSException {
        return 0;
    }

    public void setJMSExpiration(long l) throws JMSException {
    }

    public int getJMSPriority() throws JMSException {
        return priority;
    }

    public void setJMSPriority(int priority) throws JMSException {
        this.priority = priority;
    }

    public void clearProperties() throws JMSException {
        properties.clear();
    }

    public boolean propertyExists(String s) throws JMSException {
        return null != properties && properties.containsKey(s);
    }

    public boolean getBooleanProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Boolean)getProperties().get(s);
    }

    public byte getByteProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Byte)properties.get(s);
    }

    public short getShortProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Short)properties.get(s);
    }

    public int getIntProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Integer)properties.get(s);
    }

    public long getLongProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Long)properties.get(s);
    }

    public float getFloatProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Float)properties.get(s);
    }

    public double getDoubleProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (Double)properties.get(s);
    }

    public String getStringProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return (String)properties.get(s);
    }

    public Object getObjectProperty(String s) throws JMSException {
        if (null == properties) throw new JMSException("No property with name " + s + " + exists");
        return properties.get(s);
    }

    @SuppressWarnings({"unchecked"})
    public Enumeration getPropertyNames() throws JMSException {
        if (null == properties) return new CollectionEnumeration(new ArrayList<String>(1));
        return new CollectionEnumeration<String>(properties.keySet());
    }

    public void setBooleanProperty(String s, boolean b) throws JMSException {
        getProperties().put(s, b);
    }

    public void setByteProperty(String s, byte b) throws JMSException {
        getProperties().put(s, b);
    }

    public void setShortProperty(String s, short i) throws JMSException {
        getProperties().put(s, i);
    }

    public void setIntProperty(String s, int i) throws JMSException {
        getProperties().put(s, i);
    }

    public void setLongProperty(String s, long l) throws JMSException {
        getProperties().put(s, l);
    }

    public void setFloatProperty(String s, float v) throws JMSException {
        getProperties().put(s, v);
    }

    public void setDoubleProperty(String s, double v) throws JMSException {
        getProperties().put(s, v);
    }

    public void setStringProperty(String s, String s1) throws JMSException {
        getProperties().put(s, s1);
    }

    public void setObjectProperty(String s, Object o) throws JMSException {
        getProperties().put(s, o);
    }

    public void acknowledge() throws JMSException {
    }

    public void clearBody() throws JMSException {
    }

//    public Date getAddedTimestamp() {
//        return addedTimestamp;
//    }
//
//    public void setAddedTimestamp(Date addedTimestamp) {
//        this.addedTimestamp = addedTimestamp;
//    }

    private Map<String, Object> getProperties() {
        if (null == properties) {
            properties = new HashMap<String, Object>();
        }
        return properties;
    }


    @Override
    public void writeData(DataOutput dataOutput) throws IOException {

        DataSerializationHelper.writeSafeUTF(dataOutput, jmsMessageId);
        dataOutput.writeLong(jmsTimestamp);
        dataOutput.writeInt(priority);
        dataOutput.writeInt(deliveryMode);
        DataSerializationHelper.writeSafeDate(dataOutput, addedTimestamp);
        if (properties == null) {
            dataOutput.writeBoolean(true);
        } else {
            dataOutput.writeBoolean(false);
            dataOutput.writeInt(properties.size());
            for (Map.Entry<String, Object> entry : properties.entrySet()) {
                DataSerializationHelper.writeSafeUTF(dataOutput, entry.getKey());
                DataSerializationHelper.writeSafeObject(dataOutput, entry.getValue());
            }
        }
    }

    @Override
    public void readData(DataInput dataInput) throws IOException {
        jmsMessageId = DataSerializationHelper.readSafeUTF(dataInput);
        jmsTimestamp = dataInput.readLong();
        priority = dataInput.readInt();
        deliveryMode = dataInput.readInt();
        addedTimestamp = DataSerializationHelper.readSafeDate(dataInput);
        if (!dataInput.readBoolean()) {
            int size = dataInput.readInt();
            properties = new HashMap<String, Object>(size == 0 ? 8 : size);
            for (int x = 0 ; x< size; x++) {
                properties.put(DataSerializationHelper.readSafeUTF(dataInput), DataSerializationHelper.readSafeObject(dataInput));
            }
        } else {
            properties = null;
        }
    }

}
